class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        map<char, int> m;
        int n = s.size();
        int ans = 0;

        // a b c a b c b b
        // left = 0;  ->  left指向的就是窗口左边界
        // 每次往map里插入一个字符(把对应的值加1)，如果插入完该字符对应的值>1了，那就说明窗口内有重复字符了
        // 并且这个字符就是left所指向的位置，这就是要这么设计的
        // 此时把left所指向的字母在map中对应的值减1，然后再把left加1
        // 再次判断刚刚插入完该字符对应的值是否还是>1
        // 为什么要循环？看一下这个例子"pwwkew"，当插入第二个w时，很明显w的值就是2了
        // 所以窗口就应该缩减成为w这一个字符了(注意是第二个w)，但此时left依然指向p，就得往前加两次，才能指向第二个w

        int left = 0;
        for(int i = 0; i < n; i++)
        {
            m[s[i]]++;
            while(m[s[i]] > 1)
                m[s[left++]]--;
            ans = max(ans, i - left + 1);
        }
        return ans;
    }
};